/*
 * Copyright 2013 Agustina Martinez-Garcia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package uk.ljmu.qudexapps.xmllib.model;

import java.io.File;

import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.igfay.jfig.JFigException;

import uk.ljmu.fedoraifz.restrequests.FedoraOperationsAPIM;
import uk.ljmu.fedoraifz.restrequests.FedoraOperationsAPIMImpl;
import uk.ljmu.metadata.schemasutilities.DcUtilities;
import uk.ljmu.metadata.schemasutilities.SchemasProcessing;
import uk.ljmu.metadata.utilities.MetadataUtilities;
import uk.ljmu.qudexapps.xmllib.exceptions.FoxmlException;
import uk.ljmu.qudexapps.xmllib.utilities.SpreadsheetUtilities;

import fedora.fedoraSystemDef.foxml.ContentLocationType;
import fedora.fedoraSystemDef.foxml.DatastreamType;
import fedora.fedoraSystemDef.foxml.DatastreamVersionType;
import fedora.fedoraSystemDef.foxml.DigitalObjectDocument;
import fedora.fedoraSystemDef.foxml.DigitalObjectType;
import fedora.fedoraSystemDef.foxml.ObjectPropertiesType;
import fedora.fedoraSystemDef.foxml.PropertyType;
import fedora.fedoraSystemDef.foxml.StateType;
import fedora.fedoraSystemDef.foxml.XmlContentType;

/**
 * Management of operations over Foxml Beans to hold the FOXML instance before
 * ingestion in the repository
 * 
 * @author agustinamartinez
 * 
 */
public class FoxmlBeans {
	/* CONSTANTS */
	private static final String RELS_EXT_DS_NAME = "RELS-EXT";
	private static final String RELS_INT_DS_NAME = "RELS-INT";
	public static final String DC_DS_NAME = "DC";
	private static final String VERSION_SUFFIX = ".0";
	@SuppressWarnings("unused")
	private static final String QUDEX_INSTANCE = "QudexInstance";
	private static Logger log = Logger.getLogger(FoxmlBeans.class);
	private FedoraOperationsAPIM fedoraObject;

	/**
	 * @return the fedoraObject
	 */
	public FedoraOperationsAPIM getFedoraObject() {
		return fedoraObject;
	}

	/**
	 * 
	 */
	private DigitalObjectDocument foxmlDoc;

	/**
	 * 
	 * @param foxmlDoc
	 */
	public void setFoxmlDoc(DigitalObjectDocument foxmlDoc) {
		this.foxmlDoc = foxmlDoc;
		if (this.foxmlDoc.getDigitalObject() == null) {
			DigitalObjectType obj = foxmlDoc.addNewDigitalObject();
			obj.setVERSION(DigitalObjectType.VERSION.X_1_1);
			foxmlDoc.getDigitalObject().addNewObjectProperties();
		}
	}

	/**
	 * 
	 * @return
	 */
	public DigitalObjectDocument getFoxmlDoc() {
		return foxmlDoc;
	}

	/**
	 * Creates a new instance of a Foxml Document with an empty Digital object
	 * with an empty ObjectProperties element. The Fedora object for
	 * communications with the repository is created here
	 * 
	 * @throws JFigException
	 */
	// TODO Check now Exception thrown from constructor
	public FoxmlBeans() throws JFigException {
		this.foxmlDoc = DigitalObjectDocument.Factory.newInstance();
		fedoraObject = new FedoraOperationsAPIMImpl();
	}

	/**
	 * Creates a new instance of a Foxml Document composed of an empty Digital
	 * object and an empty ObjectProperties element
	 * 
	 * @param fedObj
	 *            instance of a Fedora Communications object initialized by the
	 *            caller
	 */
	public FoxmlBeans(FedoraOperationsAPIM fedObj) {
		this.foxmlDoc = DigitalObjectDocument.Factory.newInstance();
		fedoraObject = fedObj;
	}

	/**
	 * Constructor to create a Foxml document instance from file
	 * 
	 * @param foxmlXml
	 */
	public FoxmlBeans(String foxmlXml, FedoraOperationsAPIM fedObj) {

		try {
			this.foxmlDoc = DigitalObjectDocument.Factory.parse(foxmlXml);
		} catch (XmlException e) {
			log.fatal("Error: ", e);

		}
		fedoraObject = fedObj;
	}

	/**
	 * Adds a new datastream object to the current Foxml document instance
	 * 
	 * @param dsName
	 *            String representing the datastream name
	 * @param typeDS
	 *            Enum type representing the type of datastrean to add
	 * @param dsLabel
	 *            String representing the datastream title
	 * @param state
	 *            String representing the state of the datastream (A- active)
	 * @param contents
	 *            object containing the contents of the ds: either a file of a
	 *            string with the actual contents
	 * @param send
	 *            boolean, set to true updates the contents in the repository
	 *            (addDatastream results)
	 * @throws FoxmlException
	 */
	public void addDatastream(String dsName,
			DatastreamType.CONTROLGROUP.Enum typeDS, String dsLabel,
			StateType.Enum state, Object contents, String mimeType, boolean send, boolean isVersionable)
					throws FoxmlException {
		switch (typeDS.intValue()) {
		case DatastreamType.CONTROLGROUP.INT_X:
			addInlineDatastream(dsName, dsLabel, state, contents, mimeType,
					send, isVersionable);
			break;
		case DatastreamType.CONTROLGROUP.INT_M:
			addManagedDatastream(dsName, dsLabel, typeDS, state, contents,
					mimeType, send, isVersionable);
			break;
		case DatastreamType.CONTROLGROUP.INT_E:
		case DatastreamType.CONTROLGROUP.INT_R:
			addExternalDatastream(dsName, dsLabel, typeDS, state, contents,
					mimeType, send, isVersionable);
			break;
		default:
			log.fatal("In addDatastream, invalid type of datastream");
			throw new FoxmlException(
					"In addDatastream, invalid type of datastream");
		}

	}

	/**
	 * Adds a new External datastream to the current Foxml document instance
	 * 
	 * @param dsName
	 *            String representing the datastream name
	 * @param dsLabel
	 *            String representing the datastream title
	 * @param controlgroup
	 *            enum type specifying the type of datastream
	 * @param state
	 *            Enum type specifying the state of the datastream
	 * @param contents
	 *            object containing the contents of the ds: either a file of a
	 *            string with the actual contents
	 * @param mimeType
	 * @param send
	 *            boolean, set to true updates the contents in the repository
	 *            (addDatastream results)
	 * @throws FoxmlException
	 */
	private void addExternalDatastream(String dsName, String dsLabel,
			DatastreamType.CONTROLGROUP.Enum controlgroup,
			StateType.Enum state, Object contents, String mimeType, boolean send, boolean isVersionable)
					throws FoxmlException {
		DatastreamType ds;
		DatastreamVersionType dsVersion;
		ds = foxmlDoc.getDigitalObject().addNewDatastream();

		dsVersion = ds.addNewDatastreamVersion();
		// We need to add a default label, otherwise when uploaded to the
		// repository won't be
		// accessible via the HTML Fedora Interface
		dsVersion.setLABEL(!dsLabel.equals("") ? dsLabel : "default ds label");
		ds.setID(dsName);
		ds.setCONTROLGROUP(controlgroup);
		ds.setSTATE(StateType.A);
		ds.setVERSIONABLE(isVersionable);
		ContentLocationType.TYPE.Enum type = ContentLocationType.TYPE.URL;

		if (!(contents instanceof String)) {
			log
			.fatal("External datastream, content is not valid. URL must be provided.");
			throw new FoxmlException(
					"addExternalDatastream. External datastream, content is not valid. URL must be provided.");
		}
		// ADD CONTENT
		ContentLocationType xmlContentLocation = dsVersion
				.addNewContentLocation();
		xmlContentLocation.setREF((String) contents);
		xmlContentLocation.setTYPE(type);

		if (send) {
			try {
				String res = fedoraObject.addDatastream(foxmlDoc
						.getDigitalObject().getPID(), /* PID */
						ds.getID(), /* DS ID */
						String.valueOf(ds.getCONTROLGROUP()), /* controlGroup */
						(String) contents, /* dsLocation */
						"", /* ALT IDs */
						dsVersion.getLABEL(), /* Datastream label */
						String.valueOf(ds.getVERSIONABLE()), /* versionable */
						StateType.A.toString() /* dsState */, "", /* formatURI */
						"", /* checksum type */
						"", /* checksum */
						mimeType, /* mimeType */
						"External datastream ingestion to object with PID: "
						+ foxmlDoc.getDigitalObject().getPID());

				if (!res.contains(String.valueOf(HttpStatus.SC_CREATED))) {
					throw new FoxmlException(
							"DATASTREAM NOT CREATED, HTTP ERROR");
				}
			} catch (IllegalArgumentException e) {
				log.fatal(e.getMessage());
				throw new FoxmlException(e.getMessage());
			} catch (Exception e) {
				log.fatal(e.getMessage());
				throw new FoxmlException(e.getMessage());
			}
		}
	}

	/**
	 * Adds a managed datastream to the current Foxml Document instance
	 * 
	 * @param dsName
	 *            String representing the datastream name
	 * @param dsLabel
	 *            String representing the datastream title
	 * @param controlgroup
	 *            enum type specifying the type of datastream
	 * @param state
	 *            Enum type specifying the state of the datastream
	 * @param contents
	 *            object containing the contents of the ds: either a file of a
	 *            string with the actual contents
	 * @param send
	 *            boolean, set to true updates the contents in the repository
	 *            (addDatastream results)
	 * @throws FoxmlException
	 */
	private void addManagedDatastream(String dsName, String dsLabel,
			DatastreamType.CONTROLGROUP.Enum controlgroup,
			StateType.Enum state, Object contents, String mimeType, boolean send, boolean isVersionable)
					throws FoxmlException {
		DatastreamType ds;
		DatastreamVersionType dsVersion;
		ds = foxmlDoc.getDigitalObject().addNewDatastream();
		ds.setVERSIONABLE(isVersionable);
		dsVersion = ds.addNewDatastreamVersion();
		dsVersion.setLABEL(!dsLabel.equals("") ? dsLabel : "default ds label");
		ds.setID(dsName);
		ds.setCONTROLGROUP(controlgroup);
		ds.setSTATE(StateType.A);	
		ContentLocationType.TYPE.Enum type;

		// VALIDATE URL
		if (contents instanceof String) {
			// VALIDATE URL
			boolean val = SchemasProcessing.validateURL((String) contents);
			if (!val) {
				// IS NOT AN URL, CHECK OTHER POSSIBLE TYPES
				// CHECK IF IT'S AN INTERNAL_ID
				if (((String) contents).startsWith(MetadataUtilities.OBJECTID)) {
					// THE TYPE IS INTERNAL_ID
					type = ContentLocationType.TYPE.INTERNAL_ID;
				} else {// Check if it's a file path
					type = ContentLocationType.TYPE.INTERNAL_ID;
					File file = new File((String) contents);

					if (!file.exists()) {
						log.fatal("Managed datastream contents not valid");
						throw new FoxmlException(
								"Managed datastream contents not valid");
					}
				}
			} else {
				// THE TYPE IS URL
				type = ContentLocationType.TYPE.URL;
			}
			// ADD CONTENT
			ContentLocationType xmlContentLocation = ds
					.addNewDatastreamVersion().addNewContentLocation();
			xmlContentLocation.setREF((String) contents);
			xmlContentLocation.setTYPE(type);

			if (send) {
				try {

					String res = fedoraObject
							.addDatastream(
									foxmlDoc.getDigitalObject().getPID() /* PID */,
									ds.getID(), /* Datastream ID */
									DatastreamType.CONTROLGROUP.M.toString() /* controlGroup */,
									(String) contents /* dsLocation */, "", /*
									 * Alt
									 * IDs
									 */
									dsVersion.getLABEL(), /* Datastream label */
									String.valueOf(ds.getVERSIONABLE()), /* versionable */
									StateType.A.toString() /* dsState */,
									"" /* formatURI */, "" /* checksum type */,
									"", /* checksum */
									mimeType /* mimeType */,
									"Initial Managed datastream ingestion to object with PID: "
											+ foxmlDoc.getDigitalObject()
											.getPID());

					if (!res.contains(String.valueOf(HttpStatus.SC_CREATED))) {
						throw new FoxmlException(
								"DATASTREAM NOT CREATED, HTTP ERROR");
					}
				} catch (IllegalArgumentException e) {
					log.fatal(e.getMessage());
					throw new FoxmlException(e.getMessage());
				} catch (Exception e) {
					log.fatal(e.getMessage());
					throw new FoxmlException(e.getMessage());
				}
			}
		} else {
			log.fatal("External datastream, content is not valid");
			throw new FoxmlException(
					"Managed datastream, content is not valid");
		}
	}

	/**
	 * Adds an inline datastream to the current Foxml Document instance
	 * 
	 * @param dsName
	 *            String representing the datastream name
	 * @param dsLabel
	 *            String representing the datastream title
	 * @param state
	 *            Enum type specifying the state of the datastream
	 * @param contents
	 *            object containing the contents of the ds: either a file of a
	 *            string with the actual contents
	 * @param send
	 *            boolean, set to true updates the contents in the repository
	 *            (addDatastream results)
	 * @throws FoxmlException
	 */
	private void addInlineDatastream(String dsName, String dsLabel,
			StateType.Enum state, Object contents, String mimeType, boolean send, boolean isVersionable)
					throws FoxmlException {
		DatastreamType ds;
		ds = foxmlDoc.getDigitalObject().addNewDatastream();
		ds.setID(dsName);
		ds.setCONTROLGROUP(DatastreamType.CONTROLGROUP.X);
		// ACTIVE BY DEFAULT
		ds.setSTATE(StateType.A);
		// AMG - Very important. If it's RELS-EXT, has to be non versionable due to frequent updates
		// and increasing size of the object
		DatastreamVersionType dsVersion = ds.addNewDatastreamVersion();
		dsVersion.setLABEL(dsLabel);
		dsVersion.setID(ds.getID() + VERSION_SUFFIX);
		dsVersion.setMIMETYPE((ds.getID().equalsIgnoreCase(RELS_EXT_DS_NAME) || 
				ds.getID().equalsIgnoreCase(RELS_INT_DS_NAME)) ? MetadataUtilities.MIMETYPES_MAP.get("rdf") : MetadataUtilities.MIMETYPES_MAP.get("xml"));
		//TODO AMG Commented, now the parameter isVersionable is present
		//if (ds.getID().equalsIgnoreCase(QUDEX_INSTANCE) || ds.getID().equalsIgnoreCase(RELS_EXT_DS_NAME) || ds.getID().equalsIgnoreCase(RELS_INT_DS_NAME))
		//	ds.setVERSIONABLE(false);
		//else ds.setVERSIONABLE(true);
		ds.setVERSIONABLE(isVersionable);
		if (contents instanceof String) {
			if (send) {
				try {
					String res = fedoraObject
							.addDatastream(
									foxmlDoc.getDigitalObject().getPID(),
									ds.getID(),
									DatastreamType.CONTROLGROUP.X.toString() /* controlGroup */,
									(String) contents /* dsLocation */, "", /*
									 * Alt
									 * IDs
									 */
									dsVersion.getLABEL(), /* Datastream label */
									String.valueOf(ds.getVERSIONABLE()), /* versionable */
									StateType.A.toString() /* dsState */,
									"" /* formatURI */, "" /* checksum type */,
									"", /* checksum */
									mimeType /* mimeType */,
									"Initial Inline XML datastream ingestion to object with PID: "
											+ foxmlDoc.getDigitalObject()
											.getPID());
					// TODO Check errors management here
					if (!res.contains(String.valueOf(HttpStatus.SC_CREATED))
							|| !res.contains("?xml")) {
						log.fatal("DATASTREAM NOT CREATED, HTTP ERROR");
						throw new FoxmlException(
								"DATASTREAM NOT CREATED, HTTP ERROR");
					}
				} catch (IllegalArgumentException e) {
					log.fatal(e.getMessage());
					throw new FoxmlException(e.getMessage());
				} catch (Exception e) {
					log.fatal(e.getMessage());
					throw new FoxmlException(e.getMessage());
				}
			} else {
				if (((String) contents).equals("")) {
					log.fatal("Empty inline datastream contents");
					throw new FoxmlException("Empty inline datastream contents");
				}
				// ADD INLINE CONTENTS
				XmlContentType xmlContents = dsVersion.addNewXmlContent();
				try {
					xmlContents.set(XmlObject.Factory.parse((String) contents));
				} catch (XmlException e) {
					log.fatal(e.getMessage());
					throw new FoxmlException(e.getMessage());
				}
			}
		} else {
			log.fatal("In addInlineDatastream, invalid type of contents");
			throw new FoxmlException(
					"In addInlineDatastream, invalid type of contents");
		}
	}

	/**
	 * Sets the label object property of the current Foxml Document instance
	 * 
	 * @param value
	 */
	public void addLabelProperty(String value) {
		ObjectPropertiesType objProps = foxmlDoc.getDigitalObject()
				.getObjectProperties();
		PropertyType propType = objProps.addNewProperty();
		propType
		.setNAME(PropertyType.NAME.INFO_FEDORA_FEDORA_SYSTEM_DEF_MODEL_LABEL);
		propType.setVALUE(value);
	}

	/**
	 * Sets the state object property of the current Foxml Document instance
	 * 
	 * @param value
	 */
	public void addStateProperty(String value) {
		ObjectPropertiesType objProps = foxmlDoc.getDigitalObject()
				.getObjectProperties();
		// Check value
		if (value.equalsIgnoreCase(StateType.A.toString())
				|| value.equalsIgnoreCase(StateType.D.toString())
				|| value.equalsIgnoreCase(StateType.I.toString())) {
			PropertyType propType = objProps.addNewProperty();
			propType
			.setNAME(PropertyType.NAME.INFO_FEDORA_FEDORA_SYSTEM_DEF_MODEL_STATE);
			propType.setVALUE(value);
		}
	}

	/**
	 * Sets the Owner identifier object property of the current Foxml Document
	 * instance
	 * 
	 * @param value
	 */
	public void addOwnerIDProperty(String value) {
		ObjectPropertiesType objProps = foxmlDoc.getDigitalObject()
				.getObjectProperties();
		PropertyType propType = objProps.addNewProperty();
		propType
		.setNAME(PropertyType.NAME.INFO_FEDORA_FEDORA_SYSTEM_DEF_MODEL_OWNER_ID);
		propType.setVALUE(value);
	}

	/**
	 * Adds a DC datastream to the current instance of the FOXML document being
	 * created
	 * 
	 * @param xmlDoc
	 *            oai_dc XML document
	 * @param mimeType
	 *            string containing the mimeType for managed datastreams
	 * @return Foxml document modified
	 * @throws FoxmlException
	 */
	public void addDublinCoreDatastream(Document xmlDoc, String mimeType)
			throws FoxmlException {
		long iniTime = System.currentTimeMillis();
		StringBuilder sb = new StringBuilder();
		// if DC datastream with additional Metadata then the
		// "dc:identifier" field needs to be added
		if (xmlDoc == null) {
			// Return, Fedora will create its own DC datastream
			return;
		}
		Element root = xmlDoc.getRootElement();
		// AMG- Check that the namespace DC is present in the XML fragment
		Namespace dcNs = root.getNamespaceForPrefix("dc");
		if (dcNs == null) {
			root.addNamespace("dc", MetadataUtilities.MDSchemasUrl.get("dc"));
		}
		Element elem = DocumentHelper.createElement("dc:identifier");
		// AMG- Check that is not already created
		if (!root.elements().contains(elem)) {
			DcUtilities.addOAIDCproperty("dc:identifier", this.getFoxmlDoc()
					.getDigitalObject().getPID().replace(
							MetadataUtilities.OBJECTID, ""), xmlDoc);
		}

		try {
			this.addDatastream(DC_DS_NAME, /* DS name */
					DatastreamType.CONTROLGROUP.X, /* DS type */
					"Dublin core record for the object", /* LABEL */
					StateType.A, /* State type */
					xmlDoc.asXML(), /* Contents */
					mimeType, false, true); /*
					 * Send addDatastream request, false cause we want
					 * to construct DSs in the FOXML object
					 */
		} catch (FoxmlException e) {
			sb.append("Exception in addDatastream. adding DC datastream: ");
			sb.append(e.getMessage());
			log.fatal(sb.toString());
			throw new FoxmlException(sb.toString());
		}

		sb.append("Exec time addDublinCoreDatastream: ");
		sb.append(SpreadsheetUtilities.getElapsedTimeHoursMinutesSecondsString(System
				.currentTimeMillis()
				- iniTime));
		log.info(sb.toString());
	}

	/**
	 * Adds a RELS-EXT Fedora datastream to the current instance of the FOXML
	 * document being created
	 * 
	 * @param contents
	 *            string containing the DS contents
	 * @param mimeType
	 *            string containing the mimeType for managed datastreams
	 * @return Foxml document modified
	 * @throws FoxmlException
	 */
	public void addFedoraRelsExtDatastream(String contents, String mimeType)
			throws FoxmlException {
		StringBuilder sb = new StringBuilder();
		Document doc;
		String xmlData = "";

		if (contents == null || contents.equals("")) {
			// Construct document, empty contents
			try {
				sb.append(MetadataUtilities.OBJECTID);
				sb.append(this.getFoxmlDoc().getDigitalObject().getPID());
				doc = DocumentHelper.parseText(MetadataUtilities
						.getRelsExtEmptyDocument());
				Element root = doc.getRootElement();
				Element description = DocumentHelper
						.createElement("rdf:Description");
				description.addAttribute("rdf:about", sb.toString());
				sb.delete(0, sb.toString().length());
				root.add(description);
				xmlData = doc.asXML();
			} catch (Exception e) {
				sb.append("Error empty creating RELS-EXT DS: ");
				sb.append(e.getMessage());
				log.fatal(sb.toString());
			}
		} else {
			// Add Datastream
			xmlData = contents;
		}
		try {
			this.addDatastream(RELS_EXT_DS_NAME, DatastreamType.CONTROLGROUP.X,
					"RELS-EXT record for the object", StateType.A, xmlData,
					mimeType, false, true);
		} catch (FoxmlException e) {
			sb.append("Exception in addFedoraRelsExtDatastream: ");
			sb.append(e.getMessage());
			log.fatal(sb.toString());
			throw new FoxmlException(sb.toString());
		}
	}

	/**
	 * Adds a RELS-EXT Fedora datastream to the current instance of the FOXML
	 * document being created
	 * 
	 * @param contents
	 *            string containing the DS contents
	 * @param property
	 * @param value
	 * @param mimeType
	 *            string containing the mimeType for managed datastreams
	 * @return Foxml document modified
	 * @throws FoxmlException
	 */
	/*public void addFedoraRelsExtDatastream(String contents, String property,
	    String value, String mimeType) throws FoxmlException {
	StringBuilder sb = new StringBuilder();
	Document doc;
	String xmlData = "";

	if (contents == null || contents == "") {
	    // AMG- Construct document
	    try {
		sb.append(MetadataUtilities.OBJECTID);
		sb.append(this.getFoxmlDoc().getDigitalObject().getPID());
		doc = DocumentHelper.parseText(MetadataUtilities
			.getRelsExtEmptyDocument());
		Element root = doc.getRootElement();
		Element description = DocumentHelper
		.createElement("rdf:Description");
		description.addAttribute("rdf:about", sb.toString());
		sb.delete(0, sb.toString().length());
		if (property != null && property != "") {
		    // TODO Check the given property specifies a prefix, and if
		    // it is valid
		    // Namespace propertyNs =
		    // doc.getRootElement().getNamespaceForPrefix(extracted
		    // prefix);
		    // if (propertyNs == null) {
		    // doc.getRootElement().addNamespace(ns-prefix,
		    // MetadataUtilities.MDSchemasUrl.get(ns-prefix));
		    // }
		    Element elem = DocumentHelper.createElement(property);
		    // AMG- Property expressing a Fedora relationship
		    if (value != null && value != "") {
			elem.addAttribute("rdf:resource", value);
			description.add(elem);
		    }
		}
		root.add(description);
		xmlData = doc.asXML();
	    } catch (Exception e) {
		sb.append("Error creating empty RELS-EXT DS: ");
		sb.append(e.getMessage());
		log.fatal(sb.toString());
	    }
	} else if (!property.equals("") && !value.equals("")) {
	    // Add statement
	    try {
		doc = DocumentHelper.parseText(contents);
		Element root = doc.getRootElement();
		Element description = root.element("Description");
		// TODO Check the given property specifies a prefix, and if it
		// is valid
		// Namespace propertyNs =
		// doc.getRootElement().getNamespaceForPrefix(extracted prefix);
		// if (propertyNs == null) {
		// doc.getRootElement().addNamespace(ns-prefix,
		// MetadataUtilities.MDSchemasUrl.get(ns-prefix));
		// }
		Element elem = DocumentHelper.createElement(property);
		elem.addAttribute("rdf:resource", value);
		description.add(elem);
		xmlData = doc.asXML();
	    } catch (Exception e) {
		log
		.fatal("Error while creating adding properties to RELS-EXT DS");
	    }
	} else {
	    // Add empty datastream
	    xmlData = contents;
	}
	try {
	    this.addDatastream(RELS_EXT_DS_NAME, DatastreamType.CONTROLGROUP.X,
		    "RELS-EXT record for the object", StateType.A, xmlData,
		    mimeType, false);
	} catch (FoxmlException e) {
	    sb.append("Exception in addFedoraRelsExtDatastream: ");
	    sb.append(e.getMessage());
	    log.fatal(sb.toString());
	    throw new FoxmlException(sb.toString());
	}
    }*/

	public void clearObjects() {
		this.foxmlDoc = null;
		this.fedoraObject = null;
	}

	public void initFoxmlDocumentObject() {
		setFoxmlDoc(DigitalObjectDocument.Factory.newInstance());
	}

	public void initFedoraObject() throws JFigException {
		if (this.fedoraObject == null)
			this.fedoraObject = new FedoraOperationsAPIMImpl();
	}

	public void initFedoraObject(FedoraOperationsAPIM fedObj) {
		if (this.fedoraObject == null)
			this.fedoraObject = fedObj;
	}

	public void printDocumentXML() {
		foxmlDoc.dump();
		System.out.println(foxmlDoc.xmlText());
	}

	public String getFoxmlLabel() {
		PropertyType[] propArray = this.foxmlDoc.getDigitalObject().getObjectProperties().getPropertyArray();
		for(PropertyType prop : propArray) {
			if (prop.getNAME().equals(PropertyType.NAME.INFO_FEDORA_FEDORA_SYSTEM_DEF_MODEL_LABEL))
				return prop.getVALUE();
		}
		return "Title not present";
	}
	
	public static String getNextVersionDS(String id) {
		String auxId= "";
		
		int dotIndex = id.indexOf('.');
		
		if (dotIndex == -1)
			return null;
		auxId = id.substring(dotIndex + 1);
		try {
			int nextNum = Integer.parseInt(auxId);
			nextNum++;
			String auxDsName = id.substring(0, dotIndex);
			auxId = auxDsName + "." + nextNum;
			return auxId;
		} catch (NumberFormatException ex) {
			return null;
		}
	}
}
